home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
ABUSESRC.ZIP
/
AbuseSrc
/
abuse
/
src
/
newlight.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-11
|
21KB
|
889 lines
#include "light.hpp"
#include <stdlib.h>
#include "image.hpp"
#include "macs.hpp"
#include "video.hpp"
#include "palette.hpp"
#include "timing.hpp"
#include "specs.hpp"
#include "dprint.hpp"
#include "filter.hpp"
#include "video.hpp"
light_source *first_light_source=NULL;
unsigned char *white_light,*green_light;
unsigned short min_light_level=0;
extern int vmode;
int light_detail=MEDIUM_DETAIL;
long light_to_number(light_source *l)
{
if (!l) return 0;
int x=1;
for (light_source *s=first_light_source;s;s=s->next,x++)
if (s==l) return x;
return 0;
}
light_source *number_to_light(long x)
{
if (x==0) return NULL;
x--;
for (light_source *s=first_light_source;x && s;x--,s=s->next);
return s;
}
light_source *light_source::copy()
{
next=new light_source(type,x,y,inner_radius,outer_radius,xshift,yshift,next);
return next;
}
void delete_all_lights()
{
while (first_light_source)
{
light_source *p=first_light_source;
first_light_source=first_light_source->next;
delete p;
}
}
void delete_light(light_source *which)
{
if (which==first_light_source)
{
first_light_source=first_light_source->next;
delete which;
}
else
{
for (light_source *f=first_light_source;f->next!=which && f;f=f->next);
if (f)
{
f->next=which->next;
delete which;
}
}
}
void light_source::calc_range()
{
switch (type)
{
case 0 :
{ x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
} break;
case 1 :
{ x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
x2=x+(outer_radius>>xshift); y2=y;
} break;
case 2 :
{ x1=x-(outer_radius>>xshift); y1=y;
x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
} break;
case 3 :
{ x1=x; y1=y-(outer_radius>>yshift);
x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
} break;
case 4 :
{ x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
x2=x; y2=y+(outer_radius>>yshift);
} break;
case 5 :
{ x1=x; y1=y-(outer_radius>>yshift);
x2=x+(outer_radius>>xshift); y2=y;
} break;
case 6 :
{ x1=x-(outer_radius>>xshift); y1=y-(outer_radius>>yshift);
x2=x; y2=y;
} break;
case 7 :
{ x1=x-(outer_radius>>xshift); y1=y;
x2=x; y2=y+(outer_radius>>yshift);
} break;
case 8 :
{ x1=x; y1=y;
x2=x+(outer_radius>>xshift); y2=y+(outer_radius>>yshift);
} break;
case 9 :
{
x1=x;
y1=y;
x2=x+xshift;
y2=y+yshift;
} break;
}
mul_div=(1<<16)/(outer_radius-inner_radius)*64;
}
light_source::light_source(char Type, long X, long Y, long Inner_radius,
long Outer_radius, long Xshift, long Yshift, light_source *Next)
{
type=Type;
x=X; y=Y;
inner_radius=Inner_radius;
outer_radius=Outer_radius;
next=Next;
known=0;
xshift=Xshift;
yshift=Yshift;
calc_range();
}
light_source *add_light_source(char type, long x, long y,
long inner, long outer, long xshift, long yshift)
{
first_light_source=new light_source(type,x,y,inner,outer,xshift,yshift,first_light_source);
return first_light_source;
}
#define TTINTS 9
uchar *tints[TTINTS];
void calc_tint(uchar *tint, int rs, int gs, int bs, int ra, int ga, int ba, palette *pal)
{
palette npal;
memset(npal.addr(),0,256);
for (int i=0;i<256;i++)
{
npal.set(i,(int)rs,(int)gs,(int)bs);
rs+=ra; if (rs>255) rs=255; if (rs<0) rs=0;
gs+=ga; if (gs>255) gs=255; if (gs<0) gs=0;
bs+=ba; if (bs>255) bs=255; if (bs<0) bs=0;
}
filter f(pal,&npal);
filter f2(&npal,pal);
for (i=0;i<256;i++,tint++)
*tint=f2.get_mapping(f.get_mapping(i));
}
void calc_light_table(palette *pal)
{
white_light=(unsigned char *)jmalloc(256*64,"light table");
green_light=(unsigned char *)jmalloc(256*64,"green light");
for (int i=0;i<TTINTS;i++)
tints[i]=(uchar *)jmalloc(256,"color tint");
jFILE fp("light.tbl","rb");
int recalc=0;
if (fp.open_failure()) recalc=1;
else
{
if (fp.read_short()!=calc_crc((unsigned char *)pal->addr(),768))
recalc=1;
else
{
fp.read(white_light,256*64);
fp.read(green_light,256*64);
for (i=0;i<TTINTS;i++)
fp.read(tints[i],256);
}
}
if (recalc)
{
fprintf(stderr,"Palette has changed, recalculating light table...\n");
fprintf(stderr,"white : ");
for (int color=0;color<256;color++)
{
unsigned char r,g,b;
pal->get(color,r,g,b);
if (color%16==0)
fprintf(stderr,"%d ",color);
for (int intensity=63;intensity>=0;intensity--)
{
if (r>0 || g>0 || b>0)
white_light[intensity*256+color]=pal->find_closest(r,g,b);
else
white_light[intensity*256+color]=0;
if (r) r--; if (g) g--; if (b) b--;
}
}
fprintf(stderr,"green : ");
for (color=0;color<256;color++)
{
unsigned char r,g,b;
pal->get(color,r,g,b);
r=r*3/5; b=b*3/5; g+=7; if (g>255) g=255;
if (color%16==0)
fprintf(stderr,"%d ",color);
for (int intensity=63;intensity>=0;intensity--)
{
if (r>0 || g>0 || b>0)
green_light[intensity*256+color]=pal->find_closest(r,g,b);
else
green_light[intensity*256+color]=0;
if (r) r--;
if ((intensity&1)==1)
if (g) g--;
if (b) b--;
}
}
dprintf("\ncalculating tints : \n");
uchar t[TTINTS*6]={0,0,0,0,0,0, // normal
0,0,0,1,0,0, // red
0,0,0,1,1,0, // yellow
0,0,0,1,0,1, // purple
0,0,0,1,1,1, // gray
0,0,0,0,1,0, // green
0,0,0,0,0,1, // blue
0,0,0,0,1,1, // cyan
0,0,0,0,0,0 // reverse green (night vision effect)
} ;
uchar *ti=t+6;
uchar *c;
for (i=0,c=tints[0];i<256;i++,c++) *c=i; // make the normal tint (maps everthing to itself)
for (i=0,c=tints[TTINTS-1];i<256;i++,c++) // reverse green
{
int r=pal->red(i)/2,g=255-pal->green(i)-30,b=pal->blue(i)*3/5+50;
if (g<0) g=0;
if (b>255) b=0;
*c=pal->find_closest(r,g,b);
}
// make the colored tints
for (i=1;i<TTINTS-1;i++)
{
calc_tint(tints[i],ti[0],ti[1],ti[2],ti[3],ti[4],ti[5],pal);
ti+=6;
}
jFILE f("light.tbl","wb");
f.write_short(calc_crc((unsigned char *)pal->addr(),768));
f.write(white_light,256*64);
f.write(green_light,256*64);
for (int i=0;i<TTINTS;i++)
f.write(tints[i],256);
}
}
light_patch *light_patch::copy(light_patch *Next)
{
light_patch *p=new light_patch(x1,y1,x2,y2,Next);
p->total=total;
if (total)
{
p->lights=(light_source **)jmalloc(total*sizeof(light_source *),"light patches");
memcpy(p->lights,lights,total*(sizeof(light_source *)));
}
else
p->lights=NULL;
return p;
}
#define MAX_LP 10
void add_light(light_patch *&first, long x1, long y1, long x2, long y2,
light_source *who)
{
light_patch *last=NULL;
for (light_patch *p=first;p;p=p->next)
{
// first see if light patch we are adding is enclosed entirely by another patch
if (x1>=p->x1 && y1>=p->y1 && x2<=p->x2 && y2<=p->y2)
{
if (p->total==MAX_LP) return ;
if (x1>p->x1)
{
first=p->copy(first);
first->x2=x1-1;
}
if (x2<p->x2)
{
first=p->copy(first);
first->x1=x2+1;
}
if (y1>p->y1)
{
first=p->copy(first);
first->x1=x1;
first->x2=x2;
first->y2=y1-1;
}
if (y2<p->y2)
{
first=p->copy(first);
first->x1=x1;
first->x2=x2;
first->y1=y2+1;
}
p->x1=x1; p->y1=y1; p->x2=x2; p->y2=y2;
p->total++;
p->lights=(light_source **)jrealloc(p->lights,sizeof(light_source *)*p->total,"patch_list");
p->lights[p->total-1]=who;
return ;
}
// see if the patch completly covers another patch.
if (x1<=p->x1 && y1<=p->y1 && x2>=p->x2 && y2>=p->y2)
{
if (x1<p->x1)
add_light(first,x1,y1,p->x1-1,y2,who);
if (x2>p->x2)
add_light(first,p->x2+1,y1,x2,y2,who);
if (y1<p->y1)
add_light(first,p->x1,y1,p->x2,p->y1-1,who);
if (y2>p->y2)
add_light(first,p->x1,p->y2+1,p->x2,y2,who);
if (p->total==MAX_LP) return ;
p->total++;
p->lights=(light_source **)jrealloc(p->lights,sizeof(light_source *)*p->total,"patch_list");
p->lights[p->total-1]=who;
return ;
}
// see if we intersect another rect
if (!(x2<p->x1 || y2<p->y1 || x1>p->x2 || y1>p->y2))
{
int ax1,ay1,ax2,ay2;
if (x1<p->x1)
{
add_light(first,x1,max(y1,p->y1),p->x1-1,min(y2,p->y2),who);
ax1=p->x1;
} else
ax1=x1;
if (x2>p->x2)
{
add_light(first,p->x2+1,max(y1,p->y1),x2,min(y2,p->y2),who);
ax2=p->x2;
}
else
ax2=x2;
if (y1<p->y1)
{
add_light(first,x1,y1,x2,p->y1-1,who);
ay1=p->y1;
} else
ay1=y1;
if (y2>p->y2)
{
add_light(first,x1,p->y2+1,x2,y2,who);
ay2=p->y2;
} else
ay2=y2;
add_light(first,ax1,ay1,ax2,ay2,who);
return ;
}
}
}
light_patch *find_patch(int screenx, int screeny, light_patch *list)
{
for (;list;list=list->next)
{
if (screenx>=list->x1 && screenx<=list->x2 && screeny>=list->y1 && screeny<=list->y2)
return list;
}
return NULL;
}
int calc_light_value(long x, long y, light_patch *which)
{
int lv=0;
int t=which->total;
for (register int i=t-1;i>=0;i--)
{
light_source *fn=which->lights[i];
if (fn->type==9)
{
lv=fn->inner_radius;
i=0;
}
else
{
long dx=abs(fn->x-x)<<fn->xshift;
long dy=abs(fn->y-y)<<fn->yshift;
long r2;
if (dx<dy)
r2=dx+dy-(dx>>1);
else r2=dx+dy-(dy>>1);
if (r2>=fn->inner_radius)
{
if (r2<fn->outer_radius)
{
lv+=((fn->outer_radius-r2)*fn->mul_div)>>16;
}
} else lv=63;
}
}
if (lv>63) return 63;
else
return lv;
}
void reduce_patches(light_patch *f) // find constant valued patches
{
}
light_patch *make_patch_list(int cx1,int cy1,int cx2,int cy2, long screenx, long screeny)
{
light_patch *first=new light_patch(cx1,cy1,cx2,cy2,NULL);
for (light_source *f=first_light_source;f;f=f->next) // determine which lights will have effect
{
long x1=f->x1-screenx,y1=f->y1-screeny,x2=f->x2-screenx,y2=f->y2-screeny;
if (x1<cx1) x1=cx1;
if (y1<cy1) y1=cy1;
if (x2>cx2) x2=cx2;
if (y2>cy2) y2=cy2;
if (x1<=x2 && y1<=y2)
add_light(first,x1,y1,x2,y2,f);
}
reduce_patches(first);
return first;
}
void delete_patch_list(light_patch *first)
{
while (first)
{
light_patch *p=first;
first=first->next;
delete p;
}
}
#ifdef __WATCOMC__
extern "C" {
extern long MAP_PUT(long pad, long screen_addr, long remap, long w);
extern long MAP_PUT2(long dest, long screen_addr, long remap, long w);
} ;
#else
inline long MAP_PUT(long pad, long screen_addr, long remap, long w)
{ while (w--)
{
*((uchar *)(screen_addr))=*((uchar *)remap+*((uchar *)screen_addr));
screen_addr++;
}
return screen_addr;
}
inline long MAP_PUT2(long dest_addr, long screen_addr, long remap, long w)
{ while (w--)
{
*((uchar *)(dest_addr))=*((uchar *)remap+*((uchar *)screen_addr));
screen_addr++;
dest_addr++;
}
return dest_addr;
}
#endif
inline long calc_lv(light_patch *lp, long sx, long sy)
{
light_source **lon_p=lp->lights;
long lv=min_light_level;
int light_on;
for (light_on=lp->total-1;light_on>=0;light_on--)
{
light_source *fn=*lon_p;
long *dt=&(*lon_p)->type;
if (*dt==9)
{
lv=fn->inner_radius;
light_on=0;
} else
{
dt++;
int dx=abs(*dt-sx); dt++;
dx<<=*dt; dt++;
int dy=abs(*dt-sy); dt++;
dy<<=*dt; dt++;
int r2;
if (dx<dy)
r2=dx+dy-(dx>>1);
else r2=dx+dy-(dy>>1);
if (r2<*dt)
{
int v=*dt-r2; dt++;
lv+=v*(*dt)>>16;
}
}
lon_p++;
}
if (lv>63) return 63;
else return lv;
}
void light_screen(image *sc, long screenx, long screeny, uchar *light_lookup)
{
int lx_run,ly_run;
switch (light_detail)
{
case HIGH_DETAIL :
{ lx_run=2; ly_run=1; } break;
case MEDIUM_DETAIL :
{ lx_run=3; ly_run=2; } break;
case LOW_DETAIL :
{ lx_run=4; ly_run=3; } break;
case POOR_DETAIL : // low detail lighting alread taken care of.
return ;
}
short cx1,cy1,cx2,cy2;
sc->get_clip(cx1,cy1,cx2,cy2);
// sc->add_dirty(cx1,cy1,cx2,cy2);
unsigned char *mint=light_lookup+min_light_level*256;
screenx-=cx1;
screeny-=cy1;
light_patch *first=make_patch_list(cx1,cy1,cx2,cy2,screenx,screeny);
int ytry=(1<<ly_run),xtry=(1<<lx_run);
int calcx_mask=(0xefffffff-(xtry-1));
int calcy_mask=(0xefffffff-(ytry-1));
int scr_w=screen->width();
for (light_patch *lp=first;lp;lp=lp->next)
{
register int x2=lp->x2;
if (lp->total==0) // do dark patches really fast.
{
unsigned char *sl=screen->scan_line(lp->y1)+lp->x1,*dest;
#ifdef __WATCOMC__
if (get_vmode()==19) dest=(uchar *)0xa0000+lp->y1*320+lp->x1;
else dest=sl;
#else
dest=sl;
#endif
int y2=lp->y2;
for (int y=lp->y1;y<=y2;y++,sl+=scr_w,dest+=scr_w)
{
int w=lp->x2-lp->x1+1;
MAP_PUT2((long)dest,(long)sl,(long)mint,w);
}
}
else
{
int todoy;
int y2=lp->y2;
int xmask=(xtry-1);
int ymask=(ytry-1);
uchar *yaddr=screen->scan_line(lp->y1)+lp->x1,*dyaddr;
#ifdef __WATCOMC__
if (get_vmode()==19) dyaddr=((uchar *)0xa0000)+lp->y1*320+lp->x1;
else dyaddr=yaddr;
#else
dyaddr=yaddr;
#endif
for (int y=lp->y1;y<=y2;)
{
long sy=(screeny+y);
if (y+ytry>lp->y2) // see how many y lines to do for this block
todoy=lp->y2-y+1;
else todoy=ytry;
int maxy=ytry-(sy&ymask);
if (todoy>maxy)
todoy=maxy;
uchar *xaddr=yaddr,*dxaddr=dyaddr;
for (register int x=lp->x1;x<=x2;)
{
long lv=min_light_level;
unsigned char *ct;
light_source *f;
int todox;
if (x+xtry>lp->x2)
todox=lp->x2-x+1;
else todox=xtry;
int sx=(screenx+x);
int max=xtry-(sx&xmask);
if (todox>max)
todox=max;
ct=light_lookup+calc_lv(lp,sx,sy)*256;
switch (todox)
{
case 8 :
{
x+=8;
switch (todoy)
{
case 4 :
{
uchar *addr=xaddr,*daddr=dxaddr;
dxaddr=(uchar *)MAP_PUT2((long)daddr,(long)addr,(long)ct,8);
xaddr+=8;
addr+=scr_w; daddr+=scr_w;
MAP_PUT2((long)daddr,(long)addr,(long)ct,8); addr+=scr_w; daddr+=scr_w;
MAP_PUT2((long)daddr,(long)addr,(long)ct,8); addr+=scr_w; daddr+=scr_w;
MAP_PUT2((long)daddr,(long)addr,(long)ct,8);
} break;
case 3 :
{
uchar *addr=xaddr,*daddr=dxaddr;
dxaddr=(uchar *)MAP_PUT2((long)daddr,(long)addr,(long)ct,8);
xaddr+=8;
addr+=scr_w; daddr+=scr_w;
MAP_PUT2((long)daddr,(long)addr,(long)ct,8); addr+=scr_w; daddr+=scr_w;
MAP_PUT2((long)daddr,(long)addr,(long)ct,8);
} break;
case 2 :
{
uchar *addr=xaddr,*daddr=dxaddr;
dxaddr=(uchar *)MAP_PUT2((long)daddr,(long)addr,(long)ct,8);
xaddr+=8;
addr+=scr_w; daddr+=scr_w;
MAP_PUT2((long)daddr,(long)addr,(long)ct,8);
} break;
case 1 :
{ dxaddr=(uchar *)MAP_PUT((long)dxaddr,(long)xaddr,(long)ct,8);
xaddr+=8;
} break;
}
} break;
/* case 4 :
{
x+=4;
switch (todoy)
{
case 4 :
{
uchar *addr=xaddr;
xaddr=(uchar *)MAP_PUT(0,(long)addr,(long)ct,4); addr+=scr_w; daddr+=scr_w;
MAP_PUT(0,(long)addr,(long)ct,4); addr+=scr_w; daddr+=scr_w;
MAP_PUT(0,(long)addr,(long)ct,4); addr+=scr_w; daddr+=scr_w;
MAP_PUT(0,(long)addr,(long)ct,4);
} break;
case 3 :
{
uchar *addr=xaddr;
xaddr=(uchar *)MAP_PUT(0,(long)addr,(long)ct,4); addr+=scr_w; daddr+=scr_w;
MAP_PUT(0,(long)addr,(long)ct,4); addr+=scr_w; daddr+=scr_w;
MAP_PUT(0,(long)addr,(long)ct,4);
} break;
case 2 :
{
uchar *addr=xaddr;
xaddr=(uchar *)MAP_PUT(0,(long)addr,(long)ct,4); addr+=scr_w; daddr+=scr_w;
MAP_PUT(0,(long)addr,(long)ct,4);
} break;
case 1 : xaddr=(uchar *)MAP_PUT(0,(long)xaddr,(long)ct,4); break;
}
} break; */
default :
{
x+=todox;
if (todoy==1)
{
dxaddr=(uchar *)MAP_PUT2((long)dxaddr,(long)xaddr,(long)ct,todox);
xaddr+=todox;
}
else
{
uchar *addr=xaddr,*daddr=dxaddr;
dxaddr=(uchar *)MAP_PUT2((long)dxaddr,(long)xaddr,(long)ct,todox);
xaddr+=todox;
addr+=scr_w;
daddr+=scr_w;
int cc=todoy-1;
while (cc--)
{
MAP_PUT2((long)daddr,(long)addr,(long)ct,todox);
addr+=scr_w;
daddr+=scr_w;
}
}
}
}
}
int yadd=scr_w*todoy;
yaddr+=yadd;
dyaddr+=yadd;
y+=todoy;
}
}
}
while (first)
{
light_patch *p=first;
first=first->next;
delete p;
}
}
void add_light_spec(spec_directory *sd, char *level_name)
{
long size=4+4; // number of lights and minimum light levels
for (light_source *f=first_light_source;f;f=f->next)
size+=6*4+1;
sd->add(new spec_entry(SPEC_LIGHT_LIST,"lights",NULL,size,0));
}
void write_lights(jFILE *fp)
{
int t=0;
for (light_source *f=first_light_source;f;f=f->next) t++;
fp->write_long(t);
fp->write_long(min_light_level);
for (f=first_light_source;f;f=f->next)
{
fp->write_long(f->x);
fp->write_long(f->y);
fp->write_long(f->xshift);
fp->write_long(f->yshift);
fp->write_long(f->inner_radius);
fp->write_long(f->outer_radius);
fp->write_byte(f->type);
}
}
int send_lights(net_descriptor *os)
{
packet pk;
int t=0;
for (light_source *f=first_light_source;f;f=f->next) t++;
pk.write_long(t);
pk.write_short(min_light_level);
if (!os->send(pk)) return 0;
for (f=first_light_source;f;f=f->next)
{
pk.reset();
pk.write_long(f->x);
pk.write_long(f->y);
pk.write_long(f->xshift);
pk.write_long(f->yshift);
pk.write_long(f->inner_radius);
pk.write_long(f->outer_radius);
pk.write_long(f->type);
if (!os->send(pk)) return 0;
}
return 1;
}
void read_lights(spec_directory *sd, jFILE *fp, char *level_name)
{
delete_all_lights();
spec_entry *se=sd->find("lights");
if (se)
{
fp->seek(se->offset,SEEK_SET);
long t=fp->read_long();
min_light_level=fp->read_long();
light_source *last;
while (t)
{
t--;
long x=fp->read_long();
long y=fp->read_long();
long xshift=fp->read_long();
long yshift=fp->read_long();
long ir=fp->read_long();
long ora=fp->read_long();
long ty=fp->read_byte();
light_source *p=new light_source(ty,x,y,ir,ora,xshift,yshift,NULL);
if (first_light_source)
last->next=p;
else first_light_source=p;
last=p;
}
}
}
int receive_lights(net_descriptor *os)
{
packet pk;
if (!os->get(pk)) { printf("net error : light total\n"); return 0; }
long t;
if (pk.read((uchar *)&t,4)!=4)
{ printf("net error : (t) packet incomplete\n"); return 0; }
t=lltl(t);
if (pk.read((uchar *)&min_light_level,2)!=2)
{ printf("net error : (minl) packet incomplete\n"); return 0; }
min_light_level=lstl(min_light_level);
light_source *last;
printf("Reading %d lights\n",t);
while (t)
{
if (!os->get(pk)) {printf("net error : read light\n"); return 0; }
t--;
long dt[7];
if (pk.read((uchar *)dt,7*4)!=7*4) return 0;
light_source *p=new light_source(lltl(dt[6]),
lltl(dt[0]),lltl(dt[1]),
lltl(dt[4]),lltl(dt[5]),
lltl(dt[2]),lltl(dt[3]),NULL);
if (first_light_source)
last->next=p;
else first_light_source=p;
last=p;
}
return 1;
}